﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OrderAggregator.DataStorage;

namespace OrderAggregator.UI
{
    public partial class OrganizationTreeList : UserControl
    {
        private readonly TreeNode _rootNode;
        private DataStorage.Storage.OrganizationDataTable _organizationDataTable = null;
        private TreeNode _oldSelectedNode = null;

        private readonly Dictionary<DataRow, TreeNode> _nodesByRow = new Dictionary<DataRow, TreeNode>();


        public OrganizationTreeList()
        {
            InitializeComponent();

            _rootNode = new TreeNode();
            _rootNode.Text = "(Все Организации)";
            treeView1.Nodes.Add(_rootNode);

            treeView1.AfterSelect += treeView1_AfterSelect;
        }

        public void Init(DataStorage.Storage.OrganizationDataTable organizationDataTable)
        {
            if (_organizationDataTable != null)
            {
                _organizationDataTable.RowChanged -= table_RowChanged;
                _organizationDataTable.TableNewRow -= table_TableNewRow;
                _organizationDataTable.RowDeleting -= table_RowDeleted;
            }

            _organizationDataTable = organizationDataTable;
            
            _nodesByRow.Clear();

            if (_organizationDataTable == null)
            {
                _rootNode.Nodes.Clear();
                return;
            }

            UpdateNodeTree(_rootNode);

            treeView1.SelectedNode = _rootNode;
            
            treeView1.ExpandAll();

            _organizationDataTable.RowChanged += table_RowChanged;
            _organizationDataTable.TableNewRow += table_TableNewRow;
            _organizationDataTable.RowDeleting += table_RowDeleted;
        }

        

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_organizationDataTable != null)
                {
                    _organizationDataTable.RowChanged -= table_RowChanged;
                    _organizationDataTable.TableNewRow -= table_TableNewRow;
                    _organizationDataTable.RowDeleting -= table_RowDeleted;
                }
            }

            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        
        public DataStorage.Storage.OrganizationRow SelectedOrganization
        {
            get
            {
                var node = treeView1.SelectedNode;
                return node == null ? null : (DataStorage.Storage.OrganizationRow) node.Tag;
            }
            set
            {
                if (SelectedOrganization == value)
                {
                    return;
                }

                if (value == null)
                {
                    treeView1.SelectedNode = _rootNode;
                }
                else
                {
                    TreeNode node;
                    if (_nodesByRow.TryGetValue(value, out node))
                    {
                        treeView1.SelectedNode = node;
                    }
                }
            }
        }

        public event EventHandler SelectedOrganizationChanged;

        private TreeNode FindNode(Storage.OrganizationRow organizationRow)
        {
            if (organizationRow == null)
            {
                return null;
            }

            TreeNode node;
            if (_nodesByRow.TryGetValue(organizationRow, out node))
            {
                return node;
            }

            return null;
        }

        private void table_RowDeleted(object sender, DataRowChangeEventArgs e)
        {
            var dataRow = (Storage.OrganizationRow)e.Row;
            var node = FindNode(dataRow);
            if (node != null)
            {
                _nodesByRow.Remove(dataRow);
                node.Remove();
            }
        }

        private void table_TableNewRow(object sender, DataTableNewRowEventArgs e)
        {
            var dataRow = (Storage.OrganizationRow)e.Row;

            var node = new TreeNode();
            node.Tag = dataRow;
            _nodesByRow[dataRow] = node;
        }

        private void table_RowChanged(object sender, DataRowChangeEventArgs e)
        {
            var dataRow = (Storage.OrganizationRow)e.Row;
            
            if (dataRow.RowState == DataRowState.Detached)
            {
                return;
            }

            var node = FindNode(dataRow);
            
            node.Text = dataRow.Name;

            var parentNode = FindNode(dataRow.OrganizationRowParent);
            if (parentNode == null)
            {
                parentNode = _rootNode;
            }

            if (node.Parent != parentNode)
            {
                if (node.Parent != null)
                {
                    node.Parent.Nodes.Remove(node);
                }

                parentNode.Nodes.Add(node);
            }

            
        }

        private void UpdateNodeTree(TreeNode rootNode)
        {
            rootNode.Nodes.Clear();

            var allNodes = new List<TreeNode>();
            allNodes.Add(_rootNode);

            for (int i = 0; i < allNodes.Count; i++)
            {
                var node = allNodes[i];
                var parentRow = (DataStorage.Storage.OrganizationRow)node.Tag;
                var childRows = _organizationDataTable.Where(r => r.OrganizationRowParent == parentRow).ToArray();
                Array.Sort(childRows, (o1, o2) => System.Collections.Comparer.DefaultInvariant.Compare(o1.Name, o2.Name));

                foreach (DataStorage.Storage.OrganizationRow childRow in childRows)
                {
                    TreeNode childNode = new TreeNode();
                    childNode.Tag = childRow;
                    _nodesByRow[childRow] = childNode;


                    childNode.Text = childRow.Name;

                    allNodes.Add(childNode);
                    node.Nodes.Add(childNode);
                }
            }
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            FormatNode(e.Node);

            if (SelectedOrganizationChanged != null)
            {
                SelectedOrganizationChanged(this, EventArgs.Empty);
            }
        }

        private void FormatNode(TreeNode node)
        {
            if (_oldSelectedNode != null && !_oldSelectedNode.IsSelected)
            {
                _oldSelectedNode.BackColor = treeView1.BackColor;
                _oldSelectedNode.ForeColor = treeView1.ForeColor;
            }

            if (node != null && node.IsSelected)
            {
                node.ForeColor = Color.White;
                node.BackColor = Color.Gray;
                _oldSelectedNode = node;
            }
        }
    }
}
